/* **********************************************************************************
 *
 * Copyright (c) TMF.AscendedThemeKit.Unthemed.NET Project. All rights reserved.
 *
 * This source code is subject to terms and conditions of the Shared Source License
 * for TMF.AscendedThemeKit.Unthemed. A copy of the license can be found in the License.html file
 * at the root of this distribution. If you can not locate the Shared Source License
 * for TMF.AscendedThemeKit.Unthemed, please send an email to ascend_adm@hotmail.com.
 * By using this source code in any fashion, you are agreeing to be bound by
 * the terms of the Shared Source License for TMF.AscendedThemeKit.Unthemed.NET.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * **********************************************************************************/

using TMF.AscendedThemeKit.Unthemed.Resources;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.ComponentModel.Design;

namespace TMF.AscendedThemeKit.Unthemed.Windows.Forms
{
    /// <summary>
    /// A gradient animation control for winforms.
    /// </summary>
    [ToolboxBitmap(typeof(GradientAnimation), "GradientAnimation.ico")]
#if GENERAL_RELEASE
    [Designer(typeof(Ascend.Windows.Forms.Design.GradientAnimationDesigner), typeof(IDesigner))]
#else
    [Designer("TMF.AscendedThemeKit.Unthemed.Windows.Forms.Design.GradientAnimationDesigner, TMF.AscendedThemeKit.Unthemed.Design.v1.5, Culture=neutral, PublicKeyToken=5123e2ac4258b06a", typeof(IDesigner))]
#endif
    [DesignerCategory("Form")]
    [ResourceDescriptionAttribute("GradientAnimationDesription")]
    public class GradientAnimation : System.Windows.Forms.Control
    {
        /// <summary>
        /// The render class.
        /// </summary>
        internal GradientAnimationRender GradientAnimationRender;
        private bool _disposed;
        private bool _animationStarted = false;

        delegate void AnimateCallback();

        private System.ComponentModel.IContainer components = null;
        private int _interval = 200;
        private System.Threading.Timer _timer;

        /// <summary>
        /// Occurs when the Alpha property changes.
        /// </summary>
        [ResourceDescriptionAttribute("AlphaChangedDescription"), ResourceCategoryAttribute("PropertyChangedCategory"), ResourceDisplayName("DisplayNameAlphaChanged")]
        public event EventHandler AlphaChanged;

        /// <summary>
        /// Occurs when the AntiAlias property changes.
        /// </summary>
        [ResourceDescriptionAttribute("AntiAliasChangedDescription"), ResourceCategoryAttribute("PropertyChangedCategory"), ResourceDisplayName("DisplayNameAntiAliasChanged")]
        public event EventHandler AntiAliasChanged;

        /// <summary>
        /// Occurs when the Border property changes.
        /// </summary>
        [ResourceDescriptionAttribute("BorderChangedDescription"), ResourceCategoryAttribute("PropertyChangedCategory"), ResourceDisplayName("DisplayNameBorderChanged")]
        public event EventHandler BorderChanged;

        /// <summary>
        /// Occurs when the BorderColor property changes.
        /// </summary>
        [ResourceDescriptionAttribute("BorderColorChangedDescription"), ResourceCategoryAttribute("PropertyChangedCategory"), ResourceDisplayName("DisplayNameBorderColorChanged")]
        public event EventHandler BorderColorChanged;

        /// <summary>
        /// Occurs when the GradientLowColor property changes.
        /// </summary>
        [ResourceDescriptionAttribute("GradientLowColorChangedDescription"), ResourceCategoryAttribute("PropertyChangedCategory"), ResourceDisplayName("DisplayNameGradientLowColorChanged")]
        public event EventHandler GradientLowColorChanged;

        /// <summary>
        /// Occurs when the GradientHighColor property changes.
        /// </summary>
        [ResourceDescriptionAttribute("GradientHighColorChangedDescription"), ResourceCategoryAttribute("PropertyChangedCategory"), ResourceDisplayName("DisplayNameGradientHighColorChanged")]
        public event EventHandler GradientHighColorChanged;

        /// <summary>
        /// Occurs when the GradientMode property changes.
        /// </summary>
        [ResourceDescriptionAttribute("GradientModeChangedDescription"), ResourceCategoryAttribute("PropertyChangedCategory"), ResourceDisplayName("DisplayNameGradientModeChanged")]
        public event EventHandler GradientModeChanged;

        /// <summary>
        /// Gets or sets the alpha (transparancy) level (0 - 255) of the fill of the control.
        /// </summary>
        [ResourceCategoryAttribute("AppearanceCategory"), ResourceDescriptionAttribute("AlphaDescription"), ResourceDisplayName("DisplayNameAlpha"), DefaultValue(255)]
        public int Alpha
        {
            get
            {
                return this.GradientAnimationRender.Alpha;

            }

            set
            {
                if (value == this.GradientAnimationRender.Alpha)
                {
                    return;

                }

                this.GradientAnimationRender.Alpha = value;

                base.Invalidate();

                this.OnAlphaChanged(new EventArgs());

            }

        }

        /// <summary>
        /// Specifies the rendering hint for the control.
        /// </summary>
        /// <value>
        /// <para>
        /// System.Boolean . Specifies if the rendering should use antialiasing.
        /// </para>
        /// <para>
        /// This property is read/write. 
        /// </para>
        /// </value>
        [ResourceCategoryAttribute("AppearanceCategory"), ResourceDescriptionAttribute("AntiAliasDescription"), ResourceDisplayName("DisplayNameAntiAlias"), DefaultValueAttribute(false)]
        public bool AntiAlias
        {
            get
            {
                return this.GradientAnimationRender.AntiAlias;

            }

            set
            {
                if (value == this.GradientAnimationRender.AntiAlias)
                {
                    return;

                }

                this.GradientAnimationRender.AntiAlias = value;

                this.GradientAnimationRender.BitmapChange = true;

                base.Invalidate();

                this.OnAntiAliasChanged(new EventArgs());

            }

        }

        /// <summary>
        /// Gets or sets the background color of the control.
        /// </summary>
        /// <value>
        /// A Color that represents the color of the control.
        /// </value>
        [Browsable(false)]
        public override Color BackColor
        {
            get
            {
                return base.BackColor;
    
            }

            set
            {
                base.BackColor = value;

            }

        }

        /// <summary>
        /// Gets or sets the border for the control.
        /// </summary>
        /// <value>
        /// <para>
        /// Border. An object of type Border representing the control's border width characteristics.
        /// </para>
        /// <para>
        /// This property is read/write.
        /// </para>
        /// </value>
        /// <remarks>
        /// For containers such as GradientPanel and GradientCaption, the Border property gets or sets their respective border widths inside the DisplayRectangle.
        /// </remarks>
        [ResourceCategoryAttribute("AppearanceCategory"), ResourceDescriptionAttribute("BorderDescription"), ResourceDisplayName("DisplayNameBorder"), DefaultValueAttribute(typeof(Border), "0, 0, 0, 0")]
        public Border Border
        {
            get
            {
                return this.GradientAnimationRender.Border;

            }

            set
            {
                if (value == this.GradientAnimationRender.Border)
                {
                    return;

                }

                this.GradientAnimationRender.Border = value;

                this.GradientAnimationRender.BitmapChange = true;

                base.Invalidate();

                this.OnBorderChanged(new EventArgs());

            }

        }

        /// <summary>
        /// Gets or sets the border color(s) for the control.
        /// </summary>
        /// <value>
        /// <para>
        /// BorderColor. An object of type Border representing the control's border color characteristics.
        /// </para>
        /// <para>
        /// This property is read/write.
        /// </para>
        /// </value>
        /// <remarks>
        /// For containers such as GradientPanel and GradientCaption, the BorderColor property gets or sets their respective border colors inside the DisplayRectangle.
        /// </remarks>
        [ResourceCategoryAttribute("AppearanceCategory"), ResourceDescriptionAttribute("BorderColorDescription"), ResourceDisplayName("DisplayNameBorderColor"), DefaultValueAttribute(typeof(BorderColor), "Left=Color [ActiveCaption],Top=Color [ActiveCaption],Right=Color [ActiveCaption],Bottom=Color [ActiveCaption]")]
        public BorderColor BorderColor
        {
            get
            {
                return this.GradientAnimationRender.BorderColor;

            }

            set
            {
                if (value == this.GradientAnimationRender.BorderColor)
                {
                    return;

                }

                this.GradientAnimationRender.BorderColor = value;

                this.GradientAnimationRender.BitmapChange = true;

                base.Invalidate();

                this.OnBorderColorChanged(new EventArgs());

            }

        }

        /// <summary>
        /// Gets or sets the gradient high (lighter) color for the control.
        /// </summary>
        /// <value>
        /// <para>
        /// System.Drawing.Color . A Color that represents the gradient high color of the control.
        /// </para>
        /// <para>
        /// This property is read/write. 
        /// </para>
        /// </value>
        [ResourceCategoryAttribute("AppearanceCategory"), ResourceDescriptionAttribute("GradientHighColorDescription"), ResourceDisplayName("DisplayNameGradientHighColor"), DefaultValueAttribute(typeof(Color), "InactiveCaptionText")]
        public Color GradientHighColor
        {
            get
            {
                return this.GradientAnimationRender.GradientHighColor;

            }

            set
            {
                if (value == this.GradientAnimationRender.GradientHighColor)
                {
                    return;

                }

                this.GradientAnimationRender.GradientHighColor = value;
                this.BackColor = value;

                this.GradientAnimationRender.BitmapChange = true;

                base.Invalidate();

                this.OnGradientHighColorChanged(new EventArgs());

            }

        }

        /// <summary>
        /// Gets or sets the gradient low (darker) color for the control.
        /// </summary>
        /// <value>
        /// <para>
        /// System.Drawing.Color . A Color that represents the gradient low color of the control.
        /// </para>
        /// <para>
        /// This property is read/write. 
        /// </para>
        /// </value>
        [ResourceCategoryAttribute("AppearanceCategory"), ResourceDisplayName("DisplayNameGradientLowColor"), ResourceDescriptionAttribute("GradientLowColorDescription"), DefaultValueAttribute(typeof(Color), "GradientActiveCaption")]
        public Color GradientLowColor
        {
            get
            {
                return this.GradientAnimationRender.GradientLowColor;

            }

            set
            {
                if (value == this.GradientAnimationRender.GradientLowColor)
                {
                    return;

                }

                this.GradientAnimationRender.GradientLowColor = value;

                this.GradientAnimationRender.BitmapChange = true;

                base.Invalidate();

                this.OnGradientLowColorChanged(new EventArgs());

            }

        }

        /// <summary>
        /// Specifies the direction of a linear gradient.
        /// </summary>
        /// <value>
        /// <para>
        /// System.Drawing.Drawing2D.LinearGradientMode . Specifies the direction of a linear gradient.
        /// </para>
        /// <para>
        /// This property is read/write. 
        /// </para>
        /// </value>
        [ResourceCategoryAttribute("AppearanceCategory"), ResourceDescriptionAttribute("GradientModeDescription"), ResourceDisplayName("DisplayNameGradientMode"), DefaultValue(LinearGradientMode.Horizontal)]
        public LinearGradientMode GradientMode
        {
            get
            {
                return this.GradientAnimationRender.GradientMode;

            }

            set
            {
                if (value == this.GradientAnimationRender.GradientMode)
                {
                    return;

                }

                this.GradientAnimationRender.GradientMode = value;

                this.GradientAnimationRender.BitmapChange = true;

                base.Invalidate();

                this.OnGradientModeChanged(new EventArgs());

            }

        }

        /// <summary>
        /// The time between animations.
        /// </summary>
        [ResourceCategoryAttribute("BehaviorCategory"), ResourceDescriptionAttribute("IntervalDescription"), ResourceDisplayName("DisplayNameInterval"), DefaultValue(200)]
        public int Interval
        {
            get
            {
                return this._interval;

            }

            set
            {
                this._interval = value;

            }

        }

        /// <summary>
        /// The speed that the animation moves accross the control.
        /// </summary>
        [ResourceCategoryAttribute("BehaviorCategory"), ResourceDescriptionAttribute("SpeedDescription"), ResourceDisplayName("DisplayNameSpeed"), DefaultValue(10)]
        public int Speed
        {
            get
            {
                return this.GradientAnimationRender.BitmapOffset;

            }

            set
            {
                this.GradientAnimationRender.BitmapOffset = value;

            }

        }

        /// <summary>
        /// Initializes a new instance of the GradientAnimation class.
        /// </summary>
        public GradientAnimation()
        {
            this.TabStop = false;

            base.SetStyle(ControlStyles.SupportsTransparentBackColor | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.Selectable, true);
            base.BackColor = Color.FromArgb(0, SystemColors.Window);

            this.InitializeRender();

            this.GradientMode = LinearGradientMode.Horizontal;
            this.GradientHighColor = SystemColors.InactiveCaptionText;
            this.GradientLowColor = SystemColors.GradientActiveCaption;

        }

        private void Animate()
        {
            try
            {
                if (!this.Disposing && !this.IsDisposed)
                {
                    if (!this._disposed)
                    {
                        if (!this.Disposing && !this.IsDisposed)
                        {
                            if (this.InvokeRequired)
                            {
                                AnimateCallback animateCallback = new AnimateCallback(Animate);
                                try
                                {
                                    this.Invoke(animateCallback);

                                }
                                catch (ObjectDisposedException ode)
                                {
                                    Trace.WriteLine(ode.Message);

                                }
                                catch
                                {
                                    throw;

                                }

                            }
                            else
                            {
                                if (this.Created)
                                {
                                    if (!this.Disposing && !this.IsDisposed)
                                    {
                                        if (this.GradientAnimationRender.Graphics != null && this.GradientAnimationRender.DisplayRectangle != null)
                                        {
                                            this.GradientAnimationRender.MoveNext();

                                            //    this.InvokePaint(this, new PaintEventArgs(this.GradientAnimationRender.Graphics, this.GradientAnimationRender.DisplayRectangle));

                                            base.Invalidate();
                                            //this.Update();

                                        }

                                    }

                                }

                            }

                        }

                    }

                }

            }
            catch
            {
                //do nothing

            }

        }

        /// <summary>
        /// Gets the default size of the control.
        /// </summary>
        /// <value>
        /// The default Size of the control.
        /// </value>
        protected override Size DefaultSize
        {
            get
            {
                return new Size(150, 20);

            }

        }

        /// <summary>
        /// Releases the unmanaged resources used by the GradientPanel and optionally releases the managed resources.
        /// </summary>
        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
        protected override void Dispose(System.Boolean disposing)
        {
            try
            {
                if (!this._disposed)
                {
                    lock (this)
                    {
                        try
                        {
                            if (disposing)
                            {
                                if (this._timer != null)
                                {
                                    if (this._animationStarted)
                                    {
                                        this.Stop();

                                    }

                                    this._timer.Dispose();

                                }

                                ((GradientAnimationRender)this.GradientAnimationRender).Dispose();

                                if (components != null)
                                {
                                    components.Dispose();

                                }

                            }

                        }
                        catch
                        {
                            throw;

                        }
                        finally
                        {
                            this._disposed = true;

                        }
                    }

                }

            }
            catch
            {
                //do nothing

            }
            finally
            {
                base.Dispose(disposing);

            }

        }

        /// <summary>
        /// Initializes the class used for rendering. 
        /// Rendering class must be based on IGradientReder.
        /// </summary>
        protected virtual void InitializeRender()
        {
            this.GradientAnimationRender = new GradientAnimationRender();

        }

        /// <summary>
        /// Fires the event indicating that the control Alpha property has changed.  Inheriting controls should use this in favour of actually listening to the event, but should not forget to call base.OnAlphaChanged() to ensure that the event is still fired for external listeners.
        /// </summary>
        /// <param name="e">A System.EventArgs that contains the event data.</param>
        protected void OnAlphaChanged(System.EventArgs e)
        {
            if (this.AlphaChanged != null)
            {
                this.AlphaChanged(this, e);

            }

        }

        /// <summary>
        /// Fires the event indicating that the control antialias has changed.  Inheriting controls should use this in favour of actually listening to the event, but should not forget to call base.OnAntiAliasChanged() to ensure that the event is still fired for external listeners.
        /// </summary>
        /// <param name="e">A System.EventArgs that contains the event data.</param>
        protected void OnAntiAliasChanged(EventArgs e)
        {
            if (this.AntiAliasChanged != null)
            {
                this.AntiAliasChanged(this, e);

            }

        }

        /// <summary>
        /// Fires the event indicating that the control Border has changed.  Inheriting controls should use this in favour of actually listening to the event, but should not forget to call base.OnBorderChanged() to ensure that the event is still fired for external listeners.
        /// </summary>
        /// <param name="e">A System.EventArgs that contains the event data.</param>
        protected void OnBorderChanged(EventArgs e)
        {
            if (this.BorderChanged != null)
            {
                this.BorderChanged(this, e);

            }

        }

        /// <summary>
        /// Fires the event indicating that the control BorderColor has changed.  Inheriting controls should use this in favour of actually listening to the event, but should not forget to call base.OnBorderColorChanged() to ensure that the event is still fired for external listeners.
        /// </summary>
        /// <param name="e">A System.EventArgs that contains the event data.</param>
        protected void OnBorderColorChanged(EventArgs e)
        {
            if (this.BorderColorChanged != null)
            {
                this.BorderColorChanged(this, e);

            }

        }

        /// <param name="e">An System.EventArgs that contains the event data.</param>
        protected override void OnEnabledChanged(System.EventArgs e)
        {
            this.GradientAnimationRender.Enabled = this.Enabled;

            base.OnEnabledChanged(e);

        }

        /// <summary>
        /// Fires the event indicating that the control gradient high color has changed.  Inheriting controls should use this in favour of actually listening to the event, but should not forget to call base.OnGradientHighColorChanged() to ensure that the event is still fired for external listeners.
        /// </summary>
        /// <param name="e">A System.EventArgs that contains the event data.</param>
        protected void OnGradientHighColorChanged(EventArgs e)
        {
            if (this.GradientHighColorChanged != null)
            {
                this.GradientHighColorChanged(this, e);

            }

        }

        /// <summary>
        /// Fires the event indicating that the control gradient low color has changed.  Inheriting controls should use this in favour of actually listening to the event, but should not forget to call base.OnGradientLowColorChanged() to ensure that the event is still fired for external listeners.
        /// </summary>
        /// <param name="e">A System.EventArgs that contains the event data.</param>
        protected void OnGradientLowColorChanged(EventArgs e)
        {
            if (this.GradientLowColorChanged != null)
            {
                this.GradientLowColorChanged(this, e);

            }

        }

        /// <param name="e">A <see cref="T:System.Windows.Forms.PaintEventArgs"></see> that contains the event data.</param>
        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
        {
            Rectangle modifiedRectangle = new Rectangle(0, 0, this.Width, this.Height);
            this.GradientAnimationRender.DisplayRectangle = modifiedRectangle;

            this.GradientAnimationRender.Render(e);

        }

        /// <summary>
        /// Raises the SizeChanged event.
        /// </summary>
        /// <param name="e">An System.EventArgs that contains the event data.</param>
        protected override void OnSizeChanged(System.EventArgs e)
        {
            this.GradientAnimationRender.BitmapChange = true;

            base.OnSizeChanged(e);

        }

        /// <summary>
        /// Fires the event indicating that the control GradientMode has changed.  Inheriting controls should use this in favour of actually listening to the event, but should not forget to call base.OnGradientModeChanged() to ensure that the event is still fired for external listeners.
        /// </summary>
        /// <param name="e">A System.EventArgs that contains the event data.</param>
        protected void OnGradientModeChanged(EventArgs e)
        {
            if (this.GradientModeChanged != null)
            {
                this.GradientModeChanged(this, e);

            }

        }

        /// <summary>
        /// Raises the SystemColorsChanged event.
        /// </summary>
        /// <param name="e">An <see cref="T:System.EventArgs"></see> that contains the event data.</param>
        protected override void OnSystemColorsChanged(System.EventArgs e)
        {
            this.GradientAnimationRender.ResetColors();
            this.GradientAnimationRender.BitmapChange = true;

            base.OnSystemColorsChanged(e);

        }

        /// <summary>
        /// Starts the animation.
        /// </summary>
        public void Start()
        {
            try
            {
                if (!this.Disposing)
                {
                    if (!this.IsDisposed)
                    {
                        if (this._timer == null)
                        {
                            this._timer = new System.Threading.Timer(new TimerCallback(TimerProc), null, this._interval, this._interval);

                        }
                        else
                        {
                            this._timer.Change(this._interval, this._interval);

                        }

                    }

                }
            }
            catch
            {
                throw;

            }
            finally
            {
                this._animationStarted = true;

            }

        }

        /// <summary>
        /// Stops the animation.
        /// </summary>
        public void Stop()
        {
            try
            {
                if (!this.IsDisposed)
                {
                    if (this._timer != null)
                    {
                        this._timer.Change(Timeout.Infinite, Timeout.Infinite);

                        this._animationStarted = false;

                    }

                }

            }
            catch
            {
                //do nothing

            }

        }

        private void TimerProc(object state)
        {
            if (!this.Disposing)
            {
                if (!this.IsDisposed)
                {
                    this.Animate();

                }

            }

        }

    }

}
